﻿namespace TestApp.Client
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.Linq;
    using Contracts;
    using JetBrains.Annotations;
    using MvvmTools;

    internal sealed class EntitiesViewModel : NotificationModel, IEntitiesViewModel
    {
        private readonly IAggregationEntityViewModel _aggregationEntityViewModel;
        private readonly List<IEntityViewModel> _curEntities;
        private readonly IDisposable _subscription;
        private long _updatesCount;
        private AggregateType _selectedAggregate;

        public EntitiesViewModel(
            [NotNull] IDataServiceAgent sataServiceAgent,
            [NotNull] Func<IDataEntityViewModel> dataEntityViewModelFactory,
            [NotNull] Func<IAggregationEntityViewModel> aggregationEntityViewModelFactory)
        {
            Contract.Requires<ArgumentNullException>(sataServiceAgent != null);
            Contract.Requires<ArgumentNullException>(dataEntityViewModelFactory != null);
            Contract.Requires<ArgumentNullException>(aggregationEntityViewModelFactory != null);
            AllAggregates = Enum.GetValues(typeof (AggregateType)).Cast<AggregateType>().ToArray();
            _curEntities = new List<IEntityViewModel>();
            for (var i = 0; i < DataEntityDto.EntityCount; i++)
            {
                var newEntity = dataEntityViewModelFactory();
                newEntity.Index = i;
                _curEntities.Add(newEntity);
            }

            _aggregationEntityViewModel = aggregationEntityViewModelFactory();
            _curEntities.Add(_aggregationEntityViewModel);
            Entities = _curEntities;
            _subscription = sataServiceAgent.CreateEntitySource().Subscribe(UpdateEntities);
        }

        public IEnumerable<IEntityViewModel> Entities { get; private set; }

        public AggregateType SelectedAggregate
        {
            get
            {
                return _selectedAggregate;
            }

            set
            {
                if (!UpdateProperty(ref _selectedAggregate, value))
                {
                    return;
                }

                _aggregationEntityViewModel.SelectedAggregate = value;
            }
        }

        public IEnumerable<AggregateType> AllAggregates { get; private set; }

        public long UpdatesCount
        {
            get
            {
                return _updatesCount;
            }

            private set
            {
                UpdateProperty(ref _updatesCount, value);
            }
        }

        public void Dispose()
        {
            _subscription.Dispose();
        }

        private void UpdateEntities([NotNull] IEnumerable<EntityDto> entities)
        {
            Contract.Requires<ArgumentNullException>(entities != null);
            foreach (var entity in entities)
            {
                var dataEntity = entity as DataEntityDto;
                if (dataEntity != null)
                {
                    _curEntities[dataEntity.Index].Update(dataEntity);
                    UpdatesCount++;
                    OnPropertyChanged();
                    continue;
                }

                var agg = entity as AggregateEntityDto;
                if (agg != null)
                {
                    _aggregationEntityViewModel.Update(agg);
                }
            }
        }
    }
}
